#include "../StdInc.h"

namespace GSTrader
{
	namespace Indicator
	{
		KDJ::KDJ()
		{
			m_strIndicatorName = "KDJ";
			m_n = 0;
			m_nP1 = 0;
			m_nP2 = 0;

			m_pLLV = new LLVHHV;
			m_pHHV = new LLVHHV;

			m_pSmaRsv = new SMA;
			m_pSmaK = new SMA;

			m_pRSV = new CDataSeries;

			m_pK = m_pResult;
			m_pK->m_strName = "K";

			m_pD = new CIndicatorResult;
			m_pD->m_strName = "D";
			m_vResult.push_back(m_pD);

			m_pJ = new CIndicatorResult;
			m_pJ->m_strName = "J";
			m_vResult.push_back(m_pJ);
		}


		KDJ::~KDJ()
		{
			_delete(m_pLLV)
			_delete(m_pHHV)
			_delete(m_pSmaRsv)
			_delete(m_pSmaK)
			_delete(m_pRSV)
		}

		CIndicator* KDJ::CreateInstance()
		{
			return new KDJ;
		}

		void KDJ::SetParam(double* pdParam)
		{
			if (pdParam == NULL)
				return;

			m_n = (int)pdParam[0];
			m_nP1 = (int)pdParam[1];
			m_nP2 = (int)pdParam[2];

			m_pLLV->SetParam(0, m_n, bdtLow);
			m_pHHV->SetParam(1, m_n, bdtHigh);

			m_pSmaRsv->SetParam(m_nP1, 1, bdtClose);
			m_pSmaK->SetParam(m_nP2, 1, bdtClose);

			RefreshData();
		}

		void KDJ::SetInputSeries(CSeries* pSeries)
		{
			m_pLLV->SetInputSeries(pSeries);
			m_pHHV->SetInputSeries(pSeries);
		
			m_pRSV->m_nStartIndex = pSeries->m_nStartIndex;
			m_pSmaRsv->SetInputSeries(m_pRSV);

			m_pSmaK->SetInputSeries(m_pK->m_pDataSeries);

			CIndicator::SetInputSeries(pSeries);
		}

		double KDJ::Calculate(int nIndex)
		{
			if (m_pInput == NULL || m_pInput->m_nStartIndex < 0 || m_n < 0 || m_nP1 < 0 || m_nP2 < 0)
				return 0;

			m_pLLV->Calculate(nIndex);
			m_pHHV->Calculate(nIndex);

			double dHHV = m_pHHV->GetResult(nIndex);
			double dLLV = m_pLLV->GetResult(nIndex);
			double dHL = dHHV - dLLV;
			double dClose = m_pInput->GetValue(nIndex, bdtClose);

			double dRsv = 0;
			if (dHL < DBL_MIN) // 0
			{
				dRsv = 100;
			}
			else
			{
				dRsv = ((dClose - dLLV) / dHL) * 100;
			}

			m_pRSV->SetValue(nIndex, dRsv);

			m_pSmaRsv->Calculate(nIndex);
			CIndicatorResult* pSmaRsv = m_pSmaRsv->m_vResult[0];
			double dK = pSmaRsv->GetValue(nIndex);
			m_pK->m_pDataSeries->m_nStartIndex = pSmaRsv->m_pDataSeries->m_nStartIndex;
			m_pK->SetValue(nIndex, dK);

			m_pSmaK->m_pResult->m_pDataSeries->m_nStartIndex = m_pK->m_pDataSeries->m_nStartIndex + 1;
			m_pSmaK->Calculate(nIndex);
			CIndicatorResult* pSmaK = m_pSmaK->m_vResult[0];
			double dD = pSmaK->GetValue(nIndex);
			m_pD->m_pDataSeries->m_nStartIndex = pSmaK->m_pDataSeries->m_nStartIndex;
			m_pD->SetValue(nIndex, dD);

			double dJ = 3 * dK - 2 * dD;
			m_pJ->m_pDataSeries->m_nStartIndex = m_pD->m_pDataSeries->m_nStartIndex;
			m_pJ->SetValue(nIndex, dJ);

			return 1;
		}	

		void KDJ::RefreshData()
		{
			if (m_pInput == NULL || m_pInput->m_nStartIndex < 0)
			{
				m_pK->m_pDataSeries->m_nStartIndex = -1;
				m_pD->m_pDataSeries->m_nStartIndex = -1;
				m_pJ->m_pDataSeries->m_nStartIndex = -1;
				return;
			}

			int nCount = m_pInput->GetCount();
			int nStartIndex = m_pInput->m_nStartIndex;

			m_pK->m_pDataSeries->SetSize(nCount, nStartIndex);
			m_pD->m_pDataSeries->SetSize(nCount, nStartIndex);
			m_pJ->m_pDataSeries->SetSize(nCount, nStartIndex);


			m_bCalc = true;
		}
	}
}